package com.smart.opcda.service;

import cn.hutool.core.util.StrUtil;
import com.smart.opcda.constant.Constant;
import com.smart.opcda.dto.GroupSubItem;
import com.smart.opcda.dto.GroupSubItemResponse;
import com.smart.opcda.dto.GroupSubRequest;
import com.smart.opcda.entity.RegisterGroupResponse;
import com.smart.opcda.entity.TopicEntity;
import com.smart.opcda.entity.UnRegisterGroupResponse;
import com.smart.opcda.service.listener.AsyncGroupListener;
import com.smart.opcda.topic.ServerManager;
import com.smart.opcda.topic.TopicManager;
import com.smart.opcda.util.VariantUtil;
import javafish.clients.opc.JEasyOpc;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author dengqiao
 * @date 2024/3/26 10:39
 */
@Slf4j
@Service
public class OpcDAService {
    @Autowired
    private TopicManager topicManager;
    @Autowired
    private OpcDAManager opcDAManager;
    @Autowired
    private ServerManager serverManager;

    public RegisterGroupResponse registerGroup(List<GroupSubRequest> groupSubRequests, boolean isAsync) {
        RegisterGroupResponse registerGroupResponse = new RegisterGroupResponse();
        List<GroupSubRequest> successedGroups = new ArrayList<>();
        List<GroupSubRequest> faildedGroups = new ArrayList<>();
        List<GroupSubRequest> existentGroups = new ArrayList<>();
        List<GroupSubItemResponse> successedItems = new ArrayList<>();
        List<GroupSubItemResponse> faildedItems = new ArrayList<>();
        List<GroupSubItemResponse> repeatedItems = new ArrayList<>();
        if (groupSubRequests != null && groupSubRequests.size() > 0) {
            for (GroupSubRequest groupSubRequest : groupSubRequests) {
                String topicName = groupSubRequest.getTopic();
                List<GroupSubItem> groupSubItems = groupSubRequest.getItems();
                TopicEntity topicEntity = topicManager.getTopicMap().get(topicName);
                log.info("TopicName=" + topicName);
                if (topicEntity != null) {
                    String accessPath = topicEntity.getAccessPath();
                    if (StrUtil.isNotBlank(accessPath)) {
                        accessPath += ".";
                    }
                    JEasyOpc jEasyOpc = opcDAManager.getOpcInstance(topicEntity.getServerId());
                    if (jEasyOpc != null) {
                        int updateRate = groupSubRequest.getUpdateRate();
                        if (updateRate <= 0) {
                            updateRate = Constant.DEFAULTUPDATERATE;
                        }
                        String groupId = groupSubRequest.getGroupId();
                        //查找已有的group
                        OpcGroup[] opcGroups = jEasyOpc.getGroupsAsArray();
                        if (StrUtil.isBlank(groupId)) {
                            if (opcGroups.length == 0) {
                                groupId = UUID.randomUUID().toString().replaceAll("-", "");
                            } else {
                                boolean foundAuto = false;
                                for (OpcGroup opcGroup : opcGroups) {
                                    List<OpcItem> opcItems = opcGroup.getItems();
                                    int size = 0;
                                    if (groupSubItems != null) {
                                        size += groupSubItems.size();
                                    }
                                    if (opcItems.size() + size <= 1000) {
                                        groupId = opcGroup.getGroupName();
                                        foundAuto = true;
                                    }
                                }
                                if (!foundAuto) {
                                    groupId = UUID.randomUUID().toString().replaceAll("-", "");
                                }
                            }
                            groupSubRequest.setGroupId(groupId);
                        }

                        log.info("ServerId=" + topicEntity.getServerId() + ",ServerName=" + serverManager.getServerMap().get(topicEntity.getServerId()).getServerName());
                        if (groupSubItems != null && groupSubItems.size() > 0) {
                            log.info("开始向Server下注册Group");
                            boolean hasGroup = false;
                            OpcGroup group = null;
                            if (opcGroups.length > 0) {
                                for (OpcGroup opcGroup : opcGroups) {
                                    if (opcGroup.getGroupName().equals(groupId)) {
                                        group = opcGroup;
                                        hasGroup = true;
                                    }
                                }
                            }
                            if (!hasGroup) {
                                log.info("开始注册Group,GroupId=" + groupId);
                                group = new OpcGroup(groupId, true, updateRate, 0.0f);
                                if (isAsync) {
                                    group.addAsynchListener(new AsyncGroupListener(topicName));
                                }
                                jEasyOpc.addGroup(group);
                                try {
                                    jEasyOpc.registerGroup(group);
                                    jEasyOpc.updateGroups();
                                    successedGroups.add(groupSubRequest);
                                    log.info("Group注册成功,GroupId=" + groupId);
                                } catch (Exception e) {
                                    log.info("Group注册失败,GroupId=" + groupId);
                                    log.error(e.getMessage(), e);
                                    jEasyOpc.removeGroup(group);
                                    jEasyOpc.updateGroups();
                                    faildedGroups.add(groupSubRequest);
                                    group = null;
                                }
                            } else {
                                boolean foundIn = false;
                                if (successedGroups != null && successedGroups.size() > 0) {
                                    for (GroupSubRequest groupSubRequest1 : successedGroups) {
                                        if (groupSubRequest1.getGroupId().equals(groupId)) {
                                            foundIn = true;
                                        }
                                    }
                                }
                                if (!foundIn) {
                                    existentGroups.add(groupSubRequest);
                                }
                            }
                            if (group != null) {
                                log.info("开始向Group中注册Item,GroupId=" + groupId);
                                for (GroupSubItem groupSubItem : groupSubItems) {
                                    String itemId = groupSubItem.getItemId();
                                    if (StrUtil.isNotBlank(accessPath)) {
                                        itemId = accessPath + itemId;
                                    }
                                    GroupSubItemResponse groupSubItemResponse = new GroupSubItemResponse();
                                    groupSubItemResponse.setGroupId(groupId);
                                    groupSubItemResponse.setItemId(itemId);
                                    groupSubItemResponse.setItem(groupSubItem.getItemId());
                                    groupSubItemResponse.setTopicName(topicName);
                                    groupSubItemResponse.setValue(groupSubItem.getValue());
                                    boolean hasItem = false;
                                    List<OpcItem> opcGroupItems = group.getItems();
                                    if (opcGroupItems.size() > 0) {
                                        for (OpcItem opcItem : opcGroupItems) {
                                            if (opcItem.getItemName().equals(itemId)) {
                                                hasItem = true;
                                            }
                                        }
                                    }
                                    if (!hasItem) {
                                        log.info("开始注册Item,ItemId=" + itemId);
                                        OpcItem opcItem = new OpcItem(itemId, true, "");
                                        try {
                                            group.addItem(opcItem);
                                            jEasyOpc.updateGroups();
                                            jEasyOpc.registerItem(group, opcItem);
                                            successedItems.add(groupSubItemResponse);
                                            log.info("Item注册成功,ItemId=" + itemId);
                                        } catch (Exception e) {
                                            log.info("Item注册失败,ItemId=" + itemId);
                                            faildedItems.add(groupSubItemResponse);
                                            group.removeItem(opcItem);
                                            jEasyOpc.updateGroups();
                                        }
                                    } else {
                                        log.info("Item重复,ItemId=" + itemId);
                                        repeatedItems.add(groupSubItemResponse);
                                    }
                                }
                                log.info("向Group中注册Item完成,GroupId=" + groupId);
                                //检查group中是否有注册成功的点，如果没有，那么这个组要被移除
                                List<OpcItem> opcGroupItems = group.getItems();
                                if (opcGroupItems.size() == 0) {
                                    log.info("向Group注册Item失败，Group无效，将被移除，GroupId=" + groupId);
                                    try {
                                        jEasyOpc.unregisterGroup(group);
                                        jEasyOpc.removeGroup(group);
                                        jEasyOpc.updateGroups();
                                        log.info("向Group注册Item失败，Group无效，移除Group成功，GroupId=" + groupId);
                                    } catch (Exception e) {
                                        log.info("向Group注册Item失败，Group无效，移除Group失败，GroupId=" + groupId);
                                        log.error(e.getMessage(), e);
                                        jEasyOpc.removeGroup(group);
                                        jEasyOpc.updateGroups();
                                    }

                                }
                            }
                            log.info("向Server中注册Group完成");
                        } else {
                            log.info("Group下无Item,GroupId=" + groupId);
                            faildedGroups.add(groupSubRequest);
                        }
                    } else {
                        log.info("找不到TopicName对应的OpcDA客户端");
                        faildedGroups.add(groupSubRequest);
                    }
                } else {
                    log.info("找不到TopicName");
                    faildedGroups.add(groupSubRequest);
                }
            }
        } else {
            throw new IllegalArgumentException("groupSubRequests");
        }
        registerGroupResponse.setSuccessedGroups(successedGroups);
        registerGroupResponse.setFaildedGroups(faildedGroups);
        registerGroupResponse.setExistentGroups(existentGroups);
        registerGroupResponse.setSuccessedItems(successedItems);
        registerGroupResponse.setFaildedItems(faildedItems);
        registerGroupResponse.setRepeatedItems(repeatedItems);
        return registerGroupResponse;
    }

    public UnRegisterGroupResponse unRegisterGroup(List<GroupSubRequest> groupSubRequests) {
        UnRegisterGroupResponse unRegisterGroupResponse = new UnRegisterGroupResponse();
        List<GroupSubRequest> successedGroups = new ArrayList<>();
        List<GroupSubRequest> faildedGroups = new ArrayList<>();
        List<GroupSubRequest> nonexistentGroups = new ArrayList<>();
        if (groupSubRequests != null && groupSubRequests.size() > 0) {
            for (GroupSubRequest groupSubRequest : groupSubRequests) {
                String topicName = groupSubRequest.getTopic();
                log.info("TopicName=" + topicName);
                TopicEntity topicEntity = topicManager.getTopicMap().get(topicName);
                if (topicEntity != null) {
                    JEasyOpc jEasyOpc = opcDAManager.getOpcInstance(topicEntity.getServerId());
                    if (jEasyOpc != null) {
                        log.info("ServerId=" + topicEntity.getServerId() + ",ServerName=" + serverManager.getServerMap().get(topicEntity.getServerId()).getServerName());
                        log.info("开始向Server下取消注册Group");
                        OpcGroup[] opcGroups = jEasyOpc.getGroupsAsArray();
                        String groupId = groupSubRequest.getGroupId();
                        if (StrUtil.isNotBlank(groupId)) {
                            boolean isFound = false;
                            if (opcGroups.length > 0) {
                                for (OpcGroup opcGroup : opcGroups) {
                                    if (opcGroup.getGroupName().equals(groupId)) {
                                        isFound = true;
                                        try {
                                            log.info("开始取消注册Group,GroupId=" + groupId);
                                            jEasyOpc.unregisterGroup(opcGroup);
                                            jEasyOpc.removeGroup(opcGroup);
                                            jEasyOpc.updateGroups();
                                            successedGroups.add(groupSubRequest);
                                            log.info("Group取消注册成功,GroupId=" + groupId);
                                        } catch (Exception e) {
                                            log.info("Group取消注册失败,GroupId=" + groupId);
                                            log.error(e.getMessage(), e);
                                            faildedGroups.add(groupSubRequest);
                                        }
                                    }
                                }
                            }
                            if (!isFound) {
                                log.info("未找到GroupId,GroupId=" + groupId);
                                nonexistentGroups.add(groupSubRequest);
                            }
                        } else {
                            log.info("GroupId为空");
                            faildedGroups.add(groupSubRequest);
                        }
                        log.info("向Server中取消注册Group完成");
                    } else {
                        log.info("找不到TopicName对应的OpcDA客户端");
                        faildedGroups.add(groupSubRequest);
                    }
                } else {
                    log.info("找不到TopicName");
                    faildedGroups.add(groupSubRequest);
                }
            }
        } else {
            throw new IllegalArgumentException("groupSubRequests");
        }
        unRegisterGroupResponse.setSuccessedGroups(successedGroups);
        unRegisterGroupResponse.setFaildedGroups(faildedGroups);
        unRegisterGroupResponse.setNonexistentGroups(nonexistentGroups);
        return unRegisterGroupResponse;
    }

}
